#ifndef __UTILS_H__
#define __UTILS_H__
#include "graph.h"
#include "symconst.h"
#include <ginac/ginac.h>
using namespace GiNaC;

const symbol & get_symbol(const string &);

lst set2lst(const exset &);
exset lst2set(const lst &);

bool has_par_edges(Graph::edge_descriptor,Graph);
//std::vector<Graph::edge_descriptor> edges_u_v(Graph::vertex_descriptor,Graph::vertex_descriptor,Graph);
std::vector<Graph::edge_descriptor> edges_u_v(const Graph::vertex_descriptor&,const Graph::vertex_descriptor&,const Graph&);
bool isWeakConnected(Graph&);
bool isNotConnected(Graph&);
bool isConnected(Graph&);
int diagIndex(Graph&);
bool is_external_vert(Graph::vertex_descriptor,Graph&);
bool is_ext_spin_end(Graph::vertex_descriptor,Graph&);
int num_ext_vert(Graph);
void print(Graph);
ex ex_from_graph(Graph);
void inc(std::vector<bool>&);
bool is_full(std::vector<bool>);
Graphref_lst make_subgraphs(Graph&);
bool isSubgraph(Graph&,Graph&);  // True if G2 is subgraph of G1
bool isIntersected(Graph&,Graph&);  // True if G2 is intersected with G1 or G1and G2 has common parts
bool isStrongIntersected(Graph&,Graph&);// True if G1 and G2 are intersected, but not subgraphs
typedef std::list<Graphref_lst > sorted_sum_of_M_prod;
sorted_sum_of_M_prod make_terms(Graphref_lst);  
bool is_global_ext_vert(Graph::vertex_descriptor ,Graph&);
std::list<symbol> unique_symbols(ex);
typedef unsigned char rlchar;
typedef std::list<rlchar> rllist;
std::list<rllist> get_rl_lst(Graph G);
ex trace_rl(ex,rllist);
ex trace_ng(ex);
Graph fix_rl(Graph);
ex fix_rl(ex,unsigned char);
void print_rl_tree(ex);
exmap map_to_subs(exmap);
bool idx_less_comp(tuple<ex,symbol,int>,tuple<ex,symbol,int>);
bool nops_less_comp(tuple<ex,symbol,int>,tuple<ex,symbol,int>);
int loops_in_1pi_grpah(Graph);
/*
template <typename T>
std::ostream& operator << (std::ostream& os, const std::vector<T>& vec)
{
  std::copy( vec.begin(), vec.end(), std::ostream_iterator<T>( os ) );
  return os;
}

template <typename T>
std::ostream& operator << (std::ostream& os, const std::list<T>& lst)
{
  std::copy( lst.begin(), lst.end(), std::ostream_iterator<T>( os ) );
  return os;
}
*/

template <typename T>
std::ostream & operator<<(std::ostream & os, const std::vector<T>& e)
 {
     typename std::vector<T>::const_iterator i = e.begin();
     typename std::vector<T>::const_iterator vend = e.end();
 
     if (i==vend) {
         os << "()";
         return os;
     }
 
     os << "[";
     while (true) {
       os<<*(i);
         ++i;
         if (i==vend)
             break;
         os << ",";
     }
     os << "]";
 
     return os;
 }

template <typename T>
std::ostream & operator<<(std::ostream & os, const std::set<T>& e)
 {
     typename std::set<T>::const_iterator i = e.begin();
     typename std::set<T>::const_iterator vend = e.end();
 
     if (i==vend) {
         os << "<>";
         return os;
     }
 
     os << "<";
     while (true) {
       os<<*(i);
         ++i;
         if (i==vend)
             break;
         os << ",";
     }
     os << ">";
 
     return os;
 }



template <typename T1,typename T2>
  std::ostream & operator<<(std::ostream & os, const std::pair<T1,T2>& e)
 {
     os<<"{"<<e.first<<","<<e.second<<"}";
     return os;
 }


std::ostream & operator<<(std::ostream &, const expair& );


template <typename T>
std::ostream & operator<<(std::ostream & os, const std::list<T>& e)
 {
     typename std::list<T>::const_iterator i = e.begin();
     typename std::list<T>::const_iterator vend = e.end();
 
     if (i==vend) {
         os << "()";
         return os;
     }
 
     os << "(";
     while (true) {
       os<<*(i);
         ++i;
         if (i==vend)
             break;
         os << ",";
     }
     os << ")";
 
     return os;
 }

std::ostream & operator<<(std::ostream & os, const rllist& e);

#endif // __UTILS_H__
